/*
Copyright (C) 2022-2024 Inspur Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/
package jwt

import (
	"fmt"
	"icep/common/logger"
	"icep/config"
	"net/http"
	"reflect"
	"time"

	"github.com/golang-jwt/jwt/v5"
	"github.com/golang-jwt/jwt/v5/request"
)

var log = logger.GetLogger("jwt")

type Payload struct {
	UserId   string `json:"userId"`
	UserType string `json:"userType"`
	TenantId string `json:"tenantId"`
	Phone    string `json:"phone"`
	Mail     string `json:"mail"`
}

func getSecretKey() string {
	return config.Get("icep.auth.jwt.secret", "jwt@1234#icep")
}

func GenerateToken(userId, userType, tenantId, phone, mail string) string {

	token := jwt.New(jwt.SigningMethodHS256)
	claims := make(jwt.MapClaims)
	claims["exp"] = time.Now().Add(time.Second * time.Duration(config.GetInt("icep.auth.token-expire-time", 16*3600))).Unix()
	claims["iat"] = time.Now().Add(time.Hour * time.Duration(-8)).Unix()
	claims["userId"] = userId
	claims["userType"] = userType
	claims["tenantId"] = tenantId
	claims["phone"] = phone
	claims["mail"] = mail
	token.Claims = claims

	tokenString, err := token.SignedString([]byte(getSecretKey()))
	if err != nil {
		log.Errorf("generate token error: %s", err)
	}
	return tokenString
}

func ValidateToken(req *http.Request) (bool, *Payload, string) {
	tk, err := request.ParseFromRequest(req, request.OAuth2Extractor,
		func(token *jwt.Token) (interface{}, error) {
			return []byte(getSecretKey()), nil
		})

	if err == nil {
		if tk.Valid {
			userId := GetFromClaim("userId", tk.Claims)
			userType := GetFromClaim("userType", tk.Claims)
			tenantId := GetFromClaim("tenantId", tk.Claims)
			phone := GetFromClaim("phone", tk.Claims)
			mail := GetFromClaim("mail", tk.Claims)
			payloadObj := &Payload{UserId: userId, UserType: userType, TenantId: tenantId, Phone: phone, Mail: mail}
			return true, payloadObj, "success"
		}
		return false, nil, "token is not valid"
	}
	return false, nil, "unauthorized access to this resource"
}

func GetFromClaim(key string, claims jwt.Claims) string {
	v := reflect.ValueOf(claims)
	if v.Kind() == reflect.Map {
		for _, k := range v.MapKeys() {
			value := v.MapIndex(k)
			if fmt.Sprintf("%s", k.Interface()) == key {
				return fmt.Sprintf("%v", value.Interface())
			}
		}
	}
	return ""
}
